/**
 * 
 */
package cn.edu.cqu.bysj.wm.keynode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.neo4j.graphdb.Node;

import cn.edu.cqu.bysj.wm.ago.anlys.Strength;
import cn.edu.cqu.bysj.wm.ago.lp.LP;
import cn.edu.cqu.bysj.wm.ago.lp.LPCommunity;
import cn.edu.cqu.bysj.wm.def.ConstDef;
import cn.edu.cqu.bysj.wm.gui.result.DetectedResult;
import cn.edu.cqu.bysj.wm.util.CalcTime;
import cn.edu.cqu.bysj.wm.util.DoubleFormat;
import cn.edu.cqu.bysj.wm.util.KeyNodesOuput;

/**
 * @author Meng
 * 
 */
public class KeyNodes {

	// key nodes in community
	public static Map<Long, List<Node>> sLocalKeyNodes = new HashMap<Long, List<Node>>();
	public static Map<Long, List<Node>> fLocalKeyNodes = new HashMap<Long, List<Node>>();

	// global key nodes
	public static List<Node> sGlobalKeyNodes = new ArrayList<Node>();
	public static List<Node> fGlobalKeyNodes = new ArrayList<Node>();

	public static long sTimeGlobal, sTimeLocal, fTimeLocal, fTimeGlobal;
	public static String spearmanCoefficient;

	public static int[] flag;

	/**
	 * fagin search in finding global key nodes
	 * 
	 * @param lp
	 * @param k
	 *            top-k
	 */
	public static void faginGlobalKeyNodes(LP lp, int k) {
		// lp.gdb = LPRun.openDbService();
		long s = System.currentTimeMillis();
		Fagin fagin = new Fagin();
		CentralityTool cTool = new CentralityTool(lp, flag);
		fagin.FA(cTool, k);
		fGlobalKeyNodes = fagin.keyNodes;
		fTimeGlobal = CalcTime.calcRunTime(s);

		spearman(cTool);
		KeyNodesOuput.globalOutput(fGlobalKeyNodes, ConstDef.FAGIN);
		DetectedResult.setGlobalKeyNodeResult(fGlobalKeyNodes, fTimeGlobal,
				flag, cTool);

		// LPRun.closeDbService();
	}

	/**
	 * skyline search in finding global key nodes
	 * 
	 * @param lp
	 */
	public static void skylineGlobalKeyNodes(LP lp) {
		// lp.gdb = LPRun.openDbService();
		long s = System.currentTimeMillis();

		Skyline skyline = new Skyline();
		CentralityTool cTool = new CentralityTool(lp, flag);
		skyline.search(cTool);
		sGlobalKeyNodes = skyline.keyNodes;

		sTimeGlobal = CalcTime.calcRunTime(s);
		spearman(cTool);
		KeyNodesOuput.globalOutput(sGlobalKeyNodes, ConstDef.SKYLINE);
		DetectedResult.setGlobalKeyNodeResult(sGlobalKeyNodes, sTimeGlobal,
				flag, cTool);
		// LPRun.closeDbService();
	}

	/**
	 * fagin search in finding local key nodes of each community
	 * 
	 * @param lp
	 * @param percent
	 *            percent of key nodes in a community
	 */
	public static void faginLocalKeyNodes(LP lp, double percent) {
		// lp.gdb = LPRun.openDbService();
		long s = System.currentTimeMillis();

		List<Thread> threads = new ArrayList<Thread>();
		for (Map.Entry<Long, List<Node>> entry : LPCommunity.communitys
				.entrySet()) {

			long cid = entry.getKey();
			List<Node> list = entry.getValue();

			// filter community which is neither strong or week and size less
			// than nx0.006
			if (Strength.strengths.get(cid).equals(ConstDef.NEITHER)
					|| entry.getValue().size() < lp.n * 0.006) {
				continue;
			}
			// top-k of this communtiy
			int k = (int) (list.size() * percent);
			// create a new start of this communitiy
			Thread thread = new Thread(
					new FaginRunnable(lp, cid, k, list, flag));
			thread.start();
			// add thread to queue
			threads.add(thread);
		}
		while (true) {
			int flag = 0;
			for (Thread thread : threads) {
				if (thread.isAlive()) {// threads haven't finished
					flag = 1;
					break;
				}
			}
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (flag == 0) {
				break;
			}
		}
		fTimeLocal = CalcTime.calcRunTime(s);
		KeyNodesOuput.localOutput(fLocalKeyNodes, ConstDef.FAGIN);
		DetectedResult.setLocalKeyNodeResult(fLocalKeyNodes, fTimeLocal);
		// LPRun.closeDbService();
	}

	/**
	 * skyline search in finding local key nodes of each community
	 * 
	 * @param lp
	 */
	public static void skylineLocalKeyNodes(LP lp) {
		// lp.gdb = LPRun.openDbService();
		long s = System.currentTimeMillis();

		List<Thread> threads = new ArrayList<Thread>();
		for (Map.Entry<Long, List<Node>> entry : LPCommunity.communitys
				.entrySet()) {

			long cid = entry.getKey();
			List<Node> list = entry.getValue();

			// filter community which is neither strong or week and size less
			// than nx0.006
			if (Strength.strengths.get(cid).equals(ConstDef.NEITHER)
					|| entry.getValue().size() < lp.n * 0.006) {
				continue;
			}
			// create a new start of this communitiy
			Thread thread = new Thread(new SkylineRunnable(lp, cid, list, flag));
			thread.start();
			// add thread to queue
			threads.add(thread);
		}
		while (true) {
			int flag = 0;
			for (Thread thread : threads) {
				if (thread.isAlive()) {// threads haven't finished
					flag = 1;
					break;
				}
			}
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (flag == 0) {
				break;
			}
		}
		sTimeLocal = CalcTime.calcRunTime(s);
		KeyNodesOuput.localOutput(sLocalKeyNodes, ConstDef.SKYLINE);
		DetectedResult.setLocalKeyNodeResult(sLocalKeyNodes, sTimeLocal);
		// LPRun.closeDbService();
	}

	/**
	 * calculate the spearman coefficient of all pair of index
	 * 
	 * @param cTool
	 */
	public static void spearman(CentralityTool cTool) {
		spearmanCoefficient = "\n";
		for (int i = 0; i < 6; i++) {
			for (int j = i + 1; j < 6; j++) {
				if (flag[i] == 1 && flag[j] == 1) {
					spearmanCoefficient += CentralityTool.title[i] + " vs "
							+ CentralityTool.title[j] + ": "
							+ DoubleFormat.doubleFormat(cTool.spearman(i, j))
							+ "\n";
				}
			}
		}
		//KeyNodesOuput.printBuilder.append(spearmanCoefficient);
	}
}
